package org.hackystat.devcathlon.engine.event.impl;

import static org.junit.Assert.assertEquals;
import javax.xml.datatype.XMLGregorianCalendar;
import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.engine.event.Event;
import org.hackystat.devcathlon.engine.event.EventScore;
import org.hackystat.devcathlon.engine.event.EventScoreManager;
import org.hackystat.devcathlon.engine.match.Match;
import org.hackystat.devcathlon.engine.team.Team;
import org.hackystat.devcathlon.engine.test.DevcathlonTestHelper;
import org.hackystat.devcathlon.engine.user.User;
import org.hackystat.devcathlon.engine.user.UserManager;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.BeforeClass;
import org.junit.Test;



/**
 * Tests the CommitOften event.
 * 
 * @author Daniel Arakaki, Scheller Sanchez
 */
public class TestCommitOften extends DevcathlonTestHelper {

  /**Given DevEvent counter.*/
  private static int wakeupReferences = 1;
  
  /**The base score.*/
  private static int baseScore = 0;
  
  /**The deduction for not committing in time.*/
  private static int penaltyPoints = -10;
  
  /**Test team name.*/
  private String teamName = "TestTeam";
  
  /**Test team owner.*/
  private String teamOwner = "TheOwner";
  
  /**Test match.*/
  private String matchName = "TestMatch";
  
  /**Test team member 1.*/
  private String member1 = "Member1";
  
  /**Test team member 2.*/
  private String member2 = "Member2";
  
  /**
   * Sets up the configuration.
   * 
   * @throws Exception If there is a problem with the configuration.
   */
  @BeforeClass
  public static void setupConfiguration() throws Exception {
    String eventName = CommitOften.eventName;
    ConfigurationManager configManager = ConfigurationManager.getInstance();
    configManager.setBaseScoreWeight(eventName, 1);
    configManager.getConfiguration(eventName);
    configManager.setWakeupInterval(eventName, 60);
    configManager.addProperty(eventName, CommitOften.wakeupReferencesKey, 
        String.valueOf(wakeupReferences));
    configManager.addProperty(eventName, CommitOften.baseScoreKey, String.valueOf(baseScore));
    configManager.addProperty(eventName, 
        CommitOften.penaltyPointsKey, String.valueOf(penaltyPoints));
  }
  
  /**
   * Test for no commit with more than 10 DevEvents.
   * 
   * @throws Exception If error with making team.
   */
  @Test
  public void testNoTestCommit() throws Exception {
    Team team = this.makeTeam(teamName, teamOwner, member1, member2);
    User owner = team.getOwner();
    Event event = new CommitOften();
    Project project = this.getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
    int oneHour = 60;
    XMLGregorianCalendar developTime = Tstamp.incrementMinutes(Tstamp.makeTimestamp(), -oneHour);
    
    this.makeDevTimeData(owner, project, developTime, 100);
    
    XMLGregorianCalendar timestamp = Tstamp.makeTimestamp();
    EventScore score = event.computeScore(match, team, timestamp);
    EventScoreManager.getInstance().updateEventScore(score);
    assertEquals("check for score1", -10, score.getBaseScore());
    assertEquals("check for points1", -10, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Test no commit with less than 10 DevEvents.
   * 
   * @throws Exception If error with creating a team.
   */
  @Test
  public void testNoCommitTwo() throws Exception {
    Team team = this.makeTeam(teamName, teamOwner, member1, member2);
    User owner = team.getOwner();
    Event event = new CommitOften();
    Project project = this.getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
    int oneHour = 60;
    XMLGregorianCalendar developTime = Tstamp.incrementMinutes(Tstamp.makeTimestamp(), -oneHour);
    
    this.makeDevTimeData(owner, project, developTime, 45);
    
    XMLGregorianCalendar timestamp = Tstamp.makeTimestamp();
    EventScore score = event.computeScore(match, team, timestamp);
    EventScoreManager.getInstance().updateEventScore(score);
    assertEquals("check for score2", 0, score.getBaseScore());
    assertEquals("check for points2", 0, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Test no commit with 20 plus DevEvents.
   * 
   * @throws Exception If error with creating a team.
   */
  @Test
  public void testNoCommitThree() throws Exception {
    Team team = this.makeTeam(teamName, teamOwner, member1, member2);
    User owner = team.getOwner();
    Event event = new CommitOften();
    Project project = this.getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
    int oneHour = 60;
    XMLGregorianCalendar developTime = 
      Tstamp.incrementMinutes(Tstamp.makeTimestamp(), -oneHour);
    
    int teamSize = team.getMembers().size();
    UserManager manager = UserManager.getInstance();
    
    //set up members
    Object objArray[] = team.getMembers().toArray();
    User userArray[] = new User[teamSize];
    User member[] = new User[teamSize];
    
    for (int i = 0; i < teamSize; i++) {
      userArray[i] = (User)objArray[i];
      member[i] = manager.getUser(userArray[i].getEmail());
    }
    
    this.makeDevTimeData(owner, project, developTime, 60);
    this.makeDevTimeData(member[0], project, developTime, 100);
    
    XMLGregorianCalendar timestamp = Tstamp.makeTimestamp();
    EventScore score = event.computeScore(match, team, timestamp);
    EventScoreManager.getInstance().updateEventScore(score);
    assertEquals("check for score3", -20, score.getBaseScore());
    assertEquals("check for points3", -20, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Test for a commit with less than 10 DevEvents.
   * 
   * @throws Exception If error with creating a team.
   */
  @Test
  public void testCommit() throws Exception {
    Team team = this.makeTeam(teamName, teamOwner, member1, member2);
    User owner = team.getOwner();
    Event event = new CommitOften();
    Project project = this.getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
    int oneHour = 60;
    XMLGregorianCalendar developTime = Tstamp.incrementMinutes(Tstamp.makeTimestamp(), -oneHour);
    
    this.makeDevTimeData(owner, project, developTime, 45);
    this.makeCommitData(owner, project, Tstamp.makeTimestamp());
    
    XMLGregorianCalendar timestamp = Tstamp.makeTimestamp();
    EventScore score = event.computeScore(match, team, timestamp);
    EventScoreManager.getInstance().updateEventScore(score);
    assertEquals("check for score4", 0, score.getBaseScore());
    assertEquals("check for points4", 0, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Test for a commit with more than 10 DevEvents.
   * 
   * @throws Exception If error with creating a team.
   */
  @Test
  public void testCommitOne() throws Exception {
    Team team = this.makeTeam(teamName, teamOwner, member1, member2);
    User owner = team.getOwner();
    Event event = new CommitOften();
    Project project = this.getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
    int oneHour = 60;
    XMLGregorianCalendar developTime = Tstamp.incrementMinutes(Tstamp.makeTimestamp(), -oneHour);
    
    this.makeDevTimeData(owner, project, developTime, 60);
    this.makeCommitData(owner, project, Tstamp.makeTimestamp());
    
    XMLGregorianCalendar timestamp = Tstamp.makeTimestamp();
    EventScore score = event.computeScore(match, team, timestamp);
    EventScoreManager.getInstance().updateEventScore(score);
    assertEquals("check for score5", -10, score.getBaseScore());
    assertEquals("check for points5", -10, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Test for a commit in the middle of less than 10 DevEvents.
   * 
   * @throws Exception If error with creating a team.
   */
  @Test
  public void testCommitTwo() throws Exception {
    Team team = this.makeTeam(teamName, teamOwner, member1, member2);
    User owner = team.getOwner();
    Event event = new CommitOften();
    Project project = this.getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
    int oneHour = 60;
    XMLGregorianCalendar developTime = Tstamp.incrementMinutes(Tstamp.makeTimestamp(), -oneHour);
    
    this.makeDevTimeData(owner, project, developTime, 45);
    this.makeCommitData(owner, project, Tstamp.makeTimestamp());
    this.makeDevTimeData(owner, project, developTime, 40);
    
    XMLGregorianCalendar timestamp = Tstamp.makeTimestamp();
    EventScore score = event.computeScore(match, team, timestamp);
    EventScoreManager.getInstance().updateEventScore(score);
    assertEquals("check for score6", 0, score.getBaseScore());
    assertEquals("check for points6", 0, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Test for two different files one committed in 9 DevEvents and one no commit with 10 DevEvents.
   * 
   * @throws Exception If problem with creating team.
   */
  @Test
  public void testCommitThree() throws Exception {
    Team team = this.makeTeam(teamName, teamOwner, member1, member2);
    User owner = team.getOwner();
    Event event = new CommitOften();
    Project project = this.getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
    int oneHour = 60;
    XMLGregorianCalendar developTime = Tstamp.incrementMinutes(Tstamp.makeTimestamp(), -oneHour);
    
    String fileName = "/FooTwo.java";
    makeDevTimeData(owner, project, developTime, 45, fileName);
    this.makeCommitData(owner, project, Tstamp.makeTimestamp());
    this.makeDevTimeData(owner, project, developTime, 50, "/FooThree.java");
    
    XMLGregorianCalendar timestamp = Tstamp.makeTimestamp();
    EventScore score = event.computeScore(match, team, timestamp);
    EventScoreManager.getInstance().updateEventScore(score);
    assertEquals("check for score7", -10, score.getBaseScore());
    assertEquals("check for points7", -10, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
}
